package org.vectrics.mail;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.Writer;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.apache.log4j.Logger;
import org.vectrics.SystemException;
import org.vectrics.common.util.FileUtil;
import org.vectrics.common.util.StringUtils;
import org.vectrics.domain.Domain;
import org.vectrics.provider.CoreServiceLocator;

import freemarker.template.Template;

public class FileTemplateManager {
	private Logger log = Logger.getLogger(this.getClass());
	private String baseDirectory = null;
	private FreeMarkerManager freeMarkerManager = null;
	
	public FileTemplateManager() {
		this.baseDirectory = CoreServiceLocator.getConfiguration().getEmailTemplateDirectory();
		initialize();
	}
	
	public FileTemplateManager(String baseDirectory) {
		this.baseDirectory = baseDirectory;
		initialize();
	}
	
	
	public void initialize() {
		freeMarkerManager = new FreeMarkerManager(baseDirectory);
		File directory = new File(this.baseDirectory);
		if (directory.exists() == false) {
			log.warn("Email template directory does not exist: " + this.baseDirectory);
		} else {
			log.info("Checking email template files against database");
			synchronizeTemplatesWithDatabase();
		}
	}
	
    public RecipientTemplateMergeResult processTemplate(Writer writer, FileEmailTemplate template, Map parameterMap) {
    	return freeMarkerManager.processTemplate(writer, template.getFileName(), parameterMap);
    }
	

	public Template getTemplate(FileEmailTemplateCategory category, String fileName) throws IOException {
		category = CoreServiceLocator.getSystemService().findFileEmailTemplateCategory(category.getId());
		//String filePath = category.getDomain().getId().toString() 
		//		+ "/" + category.getCode() 
		//		+ "/" + fileName;
		String filePath = fileName;
		Template freeMarkerTemplate = this.freeMarkerManager.getTemplate(filePath);
		return(freeMarkerTemplate);
	}
	
	public void saveTemplateText(FileEmailTemplate template, String text) {
		if (StringUtils.isNullOrBlank(template.getFileName())) {
			template.setFileName(template.getId().toString() + ".txt");
			CoreServiceLocator.getSystemService().updateFileEmailTemplate(template);
		}
		String fileName = this.getCategoryDirectory(template.getCategory()) + "/" 
				+ template.getFileName();
		log.info("Saving template text to file" +
				"\r\n - template.id: " + template.getId() +
				"\r\n - fileName:    " + fileName
				);
		
		try {
			log.info("Saving template text to file: " + fileName);
			FileOutputStream outputFile = new FileOutputStream(fileName);
			outputFile.write(text.getBytes());
			outputFile.close();
		} catch (Exception ex) {
			throw new SystemException("Exception saving template text to file: " + fileName, ex);
		}
	}
	
	

	
	public void synchronizeTemplatesWithDatabase() {
		File directory = new File(this.baseDirectory);
		addNewFilesToDatabase(directory);
		detectDeletedFiles();
	}

	private void addNewFilesToDatabase(File baseDirectory) {
		
		
	}
	
	private void detectDeletedFiles() {
		
	}

	public String getBaseDirectory() {
		return(this.baseDirectory);
	}
	
	public String getDomainDirectory(Domain domain) {
		return this.baseDirectory + "/" + domain.getId().toString();
	}
	
	public String getCategoryDirectory(FileEmailTemplateCategory category) {
		return getDomainDirectory(category.getDomain())  + "/" + category.getCode();
	}

	
	public String getTemplateFilePath(FileEmailTemplateCategory category, Long id) {
		FileUtil.createDirectoryIfNotExist(this.getCategoryDirectory(category));
		String file = this.getCategoryDirectory(category) + "/" + id.toString() + ".txt";
		return(file);
	}

	public void scanForNewTemplateFiles() {
		Collection domains = CoreServiceLocator.getSystemService().findAllDomains();
		Iterator iter = domains.iterator();
		while (iter.hasNext()) {
			Domain domain = (Domain)iter.next();
			log.info("scanning for new template files for domain: " + domain);
			String domainDirectory = this.getDomainDirectory(domain);
			File file = new File(domainDirectory);
			
			if (file.exists()) {
				if (file.isDirectory() == false) {
					throw new SystemException("Expected directory, but found file for domain path: " + domainDirectory);
				}

				checkEachDbCategoryAgainstFiles(domain);
				
				checkFileSystemCategoryAgainstDb(domain, domainDirectory);
				
				log.debug("Check for template files and add to templates in database if not there already");
				checkFileSystemForNewTemplateFiles(domain);
			} else {
				log.info("Domain directory for templates does not exist, checking to make sure no categories or template files exist for domain, void any found for domain" +
						"\r\n - Template Directory: " + domainDirectory +
						"\r\n - Domain: " + domain
						);
			}
		}
	}

	
	private void checkFileSystemCategoryAgainstDb(Domain domain, String domainDirectory) {
		log.debug("Make sure each subdirectory has a corresponding category stored in db");
		File domainDirFile = new File(domainDirectory);
		File[] catDirectories = domainDirFile.listFiles();
		for (int i = 0; i < catDirectories.length; i++) {
			File catDirFile = catDirectories[i];
			catDirFile.isDirectory();
			log.debug("Find category corresponding to directory");
			String catCode = catDirFile.getName();
			log.info("Category directory found, searching for code: " + catCode);
			FileEmailTemplateCategory category 
				= CoreServiceLocator.getSystemService().findFileEmailTemplateCategory(domain, catCode);
			if (category == null) {
				category = new FileEmailTemplateCategory();
				category.setCode(catCode);
				category.setDescription("");
				category.setDomain(domain);
				category.setVoided(false);
				
			}
		}
	}

	private void checkEachDbCategoryAgainstFiles(Domain domain) {
		log.debug("Make sure each category still has a corresponding sub-directory, if not, then void that category");
		List categoriesForDomain = CoreServiceLocator.getSystemService().findAllEmailTemplateCategories(domain);
		Iterator catIter = categoriesForDomain.iterator();
		while (catIter.hasNext()) {
			FileEmailTemplateCategory category = (FileEmailTemplateCategory)catIter.next();
			String categoryDir = this.getCategoryDirectory(category);
			File catDirFile = new File(categoryDir);
			if (catDirFile.exists() == false) {
				if (category.getVoided() == false) {
					category.setVoided(true);
					CoreServiceLocator.getSystemService().updateFileEmailTemplateCategory(category);
				}
			} else {
				log.debug("DB Category was found in file system");
			}
		}
	}
	

	public void checkFileSystemForNewTemplateFiles(Domain domain) {
		List categoriesForDomain = CoreServiceLocator.getSystemService().findAllEmailTemplateCategories(domain);
		Iterator catIter = categoriesForDomain.iterator();
		while (catIter.hasNext()) {
			FileEmailTemplateCategory category = (FileEmailTemplateCategory)catIter.next();
			if (category.getVoided() == false) {
				String categoryDir = this.getCategoryDirectory(category);
				log.debug("Find files in category directory");
				File categoryDirectory = new File(categoryDir);
				String[] fileNames = categoryDirectory.list();
				for (int i = 0; i < fileNames.length; i++) {
					String templateFileName = fileNames[i];
					File templateFile = new File(templateFileName);
					if (templateFile.isDirectory()) {
						throw new SystemException("Found a directory stored in a template category directory - expect just files");
						
					} else {
						log.info("Found template file, checking database to see if template is registered." +
								"- Domain: " + domain +
								"- Category: " + category +
								"- File: " + templateFileName
								);
						FileEmailTemplate emailTemplate = CoreServiceLocator.getSystemService().findFileEmailTemplate(category, templateFile.getName());
						if (emailTemplate == null) {
							log.info("Email template not found in database, adding...");
							emailTemplate = new FileEmailTemplate();
							emailTemplate.setCategory(category);
							emailTemplate.setDescription("");
							emailTemplate.setDomain(domain);
							emailTemplate.setFileName(templateFile.getName());
							emailTemplate.setName(templateFile.getName());
							emailTemplate.setVoided(false);
						} else {
							if (emailTemplate.getVoided())
								emailTemplate.setVoided(true);
						}
						CoreServiceLocator.getSystemService().updateFileEmailTemplate(emailTemplate);
					}
				}
			}
		}
	}

	
	/**
	 * Return template for passed category and template code
	 * @param category
	 * @param code
	 * @return
	 */
	public FileEmailTemplate findTemplate(FileEmailTemplateCategory category, String name) {
		return(CoreServiceLocator.getSystemService().findFileEmailTemplate(category, name));
	}

	public String findTemplateBody(FileEmailTemplate template) {
		String fileAndPath = this.getCategoryDirectory(template.getCategory())
		   + "/" + template.getFileName();
		String contents = FileUtil.getFileContents(fileAndPath);
		return(contents);
	}
	
	
	public String createEmailBody(FileEmailTemplate template, ParameterObjectMap propertyMap) {
		String templateBody = findTemplateBody(template);
		
		boolean done = false;
		while (!done) {
			String newContent = this.substitueNextParameter(templateBody, propertyMap);
			if (newContent == null)
				done = true;
			else
				templateBody = newContent;
		}
		return(templateBody);
	}


	
	public String substitueNextParameter(String content, ParameterObjectMap paramMap) {
		boolean didSubstitute = false;
		String contentStr = content;
		int pos1 = contentStr.indexOf("${");
		if (pos1 >= 0) {
			int pos2 = contentStr.indexOf("}", pos1);
			if (pos2 >= 0) {
				String paramPhrase = contentStr.substring(pos1 + 2, pos2);
				String paramName = null;
				paramName = paramPhrase;
				
				String before = contentStr.substring(0, pos1);
				String after = contentStr.substring(pos2 + 1);
				
				String value = "";
				
				String defaultValue = paramMap.findObjectParameter(paramName);
				
				didSubstitute = true;
				
	
				value = defaultValue;
				if (value == null) {
					throw new RuntimeException("Could not find default answer for auto answer - param: "
							+ paramName);
				} else {
				}
				
				log.debug("Parameter: " + paramName + " = " + value);
				
				StringBuffer newContent = new StringBuffer();
				newContent.append(before);
				newContent.append(value);
				newContent.append(after);
				contentStr = newContent.toString();
			} else {
				//done = true;
			}
		} else {
			//done = true;
		}
		if (!didSubstitute)
			contentStr = null;
		return(contentStr);
	}	

	
}
